package com.bupt.utils;


import com.bupt.annotation.MParam;
import com.bupt.exception.BaseException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * redis 的基本操作
 */
public class RedisUtils {

    /*  redis 的存储前缀  */
    private static final String PROJECT_REDIS_PREFIX_DEFAULT ="user_token";

    /*  默认的时间单位  */
    //private static final TimeUnit defaultTimeUnit = TimeUnit.MINUTES;
    private static final TimeUnit defaultTimeUnit = TimeUnit.SECONDS;
    /*   默认的缓存时长  */
    private static final long defaultTimeOut = 30L;

    // 获取到存储的key
    public static String getRedisKey(String prefix, String oriKey) {
        return prefix + ":" + oriKey;
    }

    public static String getRedisKey(String oriKey) {
        return getRedisKey(PROJECT_REDIS_PREFIX_DEFAULT, oriKey);
    }

    /*   ==============   对于redis的操作   ==============      */

    // 获取到值
    public static <T> T getObjectByOriKey(@MParam("原来的key") String oriKey,
                                          @MParam("redis的操作类") RedisTemplate<String, T> redisTemplate,
                                          @MParam("需要获取的对象") Class<T> clazz) throws BaseException {
        return getObjectByOriKey(PROJECT_REDIS_PREFIX_DEFAULT, oriKey, redisTemplate, clazz);
    }

    // 设置值的操作
    public static <T> void setObjectByOriKey(String oriKey, RedisTemplate<String, T> redisTemplate, T object)
            throws BaseException {
        setObjectByOriKey(PROJECT_REDIS_PREFIX_DEFAULT, oriKey, redisTemplate, object, defaultTimeOut, defaultTimeUnit);
    }

    // 保存信息
    public static <T> void setObjectByOriKey(String oriKey, RedisTemplate<String, T> redisTemplate, T object,
                                             Long timeOut, TimeUnit timeUnit)
            throws BaseException {
        setObjectByOriKey(PROJECT_REDIS_PREFIX_DEFAULT, oriKey, redisTemplate, object, timeOut, timeUnit);
    }

    // 删除信息
    public static <T> void expireObjectByOriKey(String oriKey, RedisTemplate<String, T> redisTemplate) throws BaseException {
        expireObjectByOriKey(PROJECT_REDIS_PREFIX_DEFAULT, oriKey, redisTemplate);
    }

    /*==    带有前缀的操作    ===*/

    // 获取到值
    public static <T> T getObjectByOriKey(String prefix, String oriKey, RedisTemplate<String, T> redisTemplate, Class<T> clazz)
            throws BaseException {
        if (null == oriKey) {
            return null;
        }
        final String key = getRedisKey(prefix, oriKey);
        ValueOperations<String, T> valueOperations = redisTemplate.opsForValue();
        T o = valueOperations.get(key);
        return o;
    }

    // 设置值的操作
    public static <T> void setObjectByOriKey(String prefix, String oriKey, RedisTemplate<String, T> redisTemplate, T object)
            throws BaseException {
        setObjectByOriKey(prefix, oriKey, redisTemplate, object, defaultTimeOut, defaultTimeUnit);
    }

    // 保存信息
    public static <T> void setObjectByOriKey(String prefix, String oriKey, RedisTemplate<String, T> redisTemplate,
                                             T object, final Long timeOut, final TimeUnit timeUnit) throws BaseException {
        String key = getRedisKey(prefix, oriKey);
        ValueOperations<String, T> valueOperations = redisTemplate.opsForValue();
        LocalVerify.verifyObject(timeOut, "timeOut");
        valueOperations.set(key, object, timeOut, timeUnit);
    }

    // 删除信息
    public static <T> void expireObjectByOriKey(String prefix, String oriKey, RedisTemplate<String, T> redisTemplate) throws BaseException {
        String key = getRedisKey(prefix, oriKey);
        ValueOperations<String, T> valueOperations = redisTemplate.opsForValue();
        valueOperations.set(key, null, 1, TimeUnit.SECONDS);
    }
    /*=============  下面是jedis的操作    ================*/


    // 获取到值
    public static <T> T getObjectByOriKey(String prefix, String oriKey, JedisPool jedisPool, Class<T> clazz)
            throws BaseException {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            final String key = getRedisKey(prefix, oriKey);
            byte[] bytes = jedis.get(key.getBytes(StandardCharsets.UTF_8));
            // 关闭来连接
            if (bytes != null && bytes.length > 0) {
                return ProtostuffUtils.deserialize(bytes, clazz);
            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("系统正忙，请稍后再试");
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
    }

    // 设置值的操作
    public static void setObjectByOriKey(String prefix, String oriKey, JedisPool jedisPool, Object object)
            throws BaseException {
        setObjectByOriKey(prefix, oriKey, jedisPool, object, defaultTimeOut, defaultTimeUnit, true);
    }

    // 保存信息
    public static void setObjectByOriKey(String prefix, String oriKey, JedisPool jedisPool, Object object,
                                         final Long timeOut, final TimeUnit timeUnit, boolean isHaveTimeLimit)
            throws BaseException {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            final String key = getRedisKey(prefix, oriKey);
            byte[] bytes = ProtostuffUtils.serialize(object);
            jedis.set(key.getBytes(StandardCharsets.UTF_8), bytes);
            if (isHaveTimeLimit) {
                jedis.expire(key.getBytes(StandardCharsets.UTF_8), (int) timeUnit.toSeconds(timeOut));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
    }

    // 删除信息
    public static void expireObjectByOriKey(String prefix, String oriKey, JedisPool jedisPool) throws BaseException {
        final String key = getRedisKey(prefix, oriKey);
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.pexpire(key.getBytes(StandardCharsets.UTF_8), TimeUnit.SECONDS.toMillis(1));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
    }
}

